package com.h2cloud.JUCTest.cas;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Package: com.h2cloud.JUCTest.cas
 * @ClassName: AtomicIntegerTest
 * @Author: h2cloud
 * @CreateTime: 2022/5/30 4:28 下午
 * @Description:
 */
public class AtomicIntegerTest {
	public static void main(String[] args) {
		Account.demo(new AccountCas(10000));
	}
}

interface Account {
	// 获取余额
	Integer getBalance();

	// 取款
	void withdraw(Integer amount);

	/**
	 * 方法内会启动 1000 个线程，每个线程做 -10 元 的操作
	 * 如果初始余额为 10000 那么正确的结果应当是 0
	 */
	static void demo(Account account) {
		List<Thread> ts = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			ts.add(new Thread(() -> {
				account.withdraw(10);
			}));
		}
		long start = System.nanoTime();
		ts.forEach(Thread::start);
		ts.forEach(t -> {
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		long end = System.nanoTime();
		System.out.println(account.getBalance()
				+ " cost: " + (end-start)/1000_000 + " ms");
	}
}

class AccountCas implements Account {

	AtomicInteger balance;

	public AccountCas(Integer balance) {
		this.balance = new AtomicInteger(balance);
	}

	@Override
	public Integer getBalance() {
		return balance.get();
	}

	@Override
	public void withdraw(Integer amount) {
		// 核心代码
		while (true) {
			// 获取余额的最新值
			int prev = balance.get();
			// 要修改的余额
			int next = prev - amount;
			// 真正修改
			if (balance.compareAndSet(prev, next)) {
				break;
				// 如果最新的余额与之前的余额不一致继续下一轮循环，一致则退出循环
			}
			// 可以简化为下面的方法
			// balance.addAndGet(-1 * amount);
		}
	}
}
